package com.ruoyi.chat.websocket;


import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.ruoyi.chat.config.CustomSpringConfigurator;
import com.ruoyi.chat.domain.ChatMessage;
import com.ruoyi.chat.util.ChatMessageDecoder;
import com.ruoyi.chat.util.ChatMessageEncoder;
import com.ruoyi.chat.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.LongStream;

@Component
@ServerEndpoint(
        value = "/userfunc/chat/{id}",
        configurator = CustomSpringConfigurator.class,
        decoders = {ChatMessageDecoder.class},
        encoders = {ChatMessageEncoder.class}
)
public class WebSocketServer {
    private Session session;
    private final Gson gson;

    private final RedisUtil redis;
    private static final Map<Long,Session> WEBSOCKET_MAP = new ConcurrentHashMap<>();

    @Autowired
    public WebSocketServer(RedisUtil redis) {
        this.gson = new Gson();
        this.redis = redis;
    }

    @OnOpen
    public void onOpen(@PathParam("id") Long id, Session session) {
        System.out.println("Opening");
        this.session = session;
        WEBSOCKET_MAP.put(id, session);
    }

    @OnMessage
    public void onMessage(ChatMessage message) throws IOException {

        //print the message
        System.out.println(message);
        // Generate a key for the message.
        String key = LongStream.of(message.getFrom(), message.getTo())
                .sorted()
                .mapToObj(String::valueOf)
                .collect(Collectors.joining("-"));
        // Save the message to Redis.
        redis.set(key, message);
        if(WEBSOCKET_MAP.get(message.getTo())!=null) {
            WEBSOCKET_MAP.get(message.getTo()).getBasicRemote().sendText(gson.toJson(message));
        }
    }

    // This method is called when the connection is closed,
    // and the session is removed from the WEBSOCKET_MAP.
    @OnClose
    public void onClose() {
        System.out.println("Closing");
        for (Map.Entry<Long, Session> entry : WEBSOCKET_MAP.entrySet()) {
            if (entry.getValue().equals(session)) {
                WEBSOCKET_MAP.remove(entry.getKey());
                return;
            }
        }
    }
    @OnError
    public void onError(Throwable error) {
        System.out.println("Error!");
        error.printStackTrace();
    }
}
